<!DOCTYPE html>
<html dir="ltr" lang="en-US">

  <head>
    <link href='https://fonts.googleapis.com/css?family=Oswald:400,700|Anonymous+Pro:400,400italic,700,700italic|Open+Sans:400italic,700italic,400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="96x96" href="favicon-96x96.png">
    <link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">

    <title> Jodd µicro-frameworks </title>
    <meta name="description" content="open-source jodd µicro frameworks tutorial">
    <link rel="stylesheet" href="style.css">
  </head>

  <body>

    <div class="animated-logo">
      <img src="jodd-logo.svg" alt="Jodd paperplane">
    </div>

    <!-- BLOCK 0 ------------------------------------------------------------------------------------------------------------>

    <div id="block0" class="section">
      <div class="content">
        <h1>Jodd <em><span>&#181;icro</span></em> frameworks</h1>

        <div class="text">

          <p id="mission">
            We want to inspire the world to create. To use tech skills and build something truly... Awesome. Beautiful. Helpful. Impactful. Now you can produce lightweight code and focus on unleashing your full potential. Jodd is a set of developer-friendly and open-source Java micro-frameworks. It's designed to make things simple, but not simpler.
          </p>

          <p>
            This tutorial is a good place to get an overview of how Jodd works. That's what we have here: a step-by-step example of how to build a web application using Jodd only. In just 30 minutes, you will get from "zero to hero".
          </p>

          <p>
            The tutorial explains how to make a simple web app from scratch: an app that shows messages and message comments stored in the database, just like a simple blog.
          </p>

          <p>
            Let's go!
          </p>

          <h2>
            <a href="http://jodd.org">http://jodd.org</a>
          </h2>
        </div>
      </div>
    </div>
    <!-- / section -->


    <div id="block1" class="section">
      <a id="1"></a>
      <div id="scroller-anchor-1"></div>
      <a id="scroller-1" href="#1" class="scroller">
        <div class="circle">1</div>
      </a>
      <div class="vertical-line"></div>
      <div class="content">
        <div class="text">
          <h2>Prepare Yourself</h2>
          <p>
            The first step is not about Jodd at all. Instead, we will lay down the infrastructure: project folders, Gradle, Tomcat, and MySql.
          </p>
          <p class="info">
            Please <a href="https://github.com/oblac/tutorial">check out this tutorial</a> - we have prepared all the files you need!
          </p>
          <h3>Folders</h3>
          <p>
            In the project's root, create <a href="https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html" target="_blank">a standard Maven folder layout</a> for web projects.
          <p>

            <div class="more m1">
              <pre>
                  <code>
/root
    /src
      /main
          /java
          /resources
          /webapp
      /test</code>
                  </pre>
              </div>

              <h3>Gradle</h3>
              <p>
                We will use <a href="http://www.gradle.org/" target="_blank">Gradle</a> for building; make sure you have it installed. Create a simple <code>build.gradle</code> script and add a single dependency to <a href="http://jodd.org/joy" title="What is Jodd Joy?">Jodd Joy</a>. That's all we need for now :)
              </p>
              <div class="more m1">
                <pre>
                  <code>
apply plugin: 'war'
version = '1.0'
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.jodd:jodd-joy:4.1.1'
}</code>
          </pre>
          <p>
            Execute the following command in the project's root: <code>gradle wrapper</code> to initialize your Gradle project. This will create the shell script <code>gradlew</code> in your root which you can use from now on to run the build process.
          </p>
        </div>
        <h3>IDE</h3>
        <p>
          Once you set the Gradle, open the project in your IDE. Create a web artifact that can be deployed.
          <a href="http://www.jetbrains.com/idea/" target="_blank">IntelliJ IDEA</a> works nicely with this setup.
        </p>
        <h3>Database</h3>
        <p>
          It's time to set up the database: <code>jodd-tutorial</code> in the <a href="http://www.mysql.com/" target="_blank">MySql</a>. There are just two tables: <code>jd_message</code> and <code>jd_response</code>: one message may contain several comments. Yes, we've made a bad decision by naming the 'comments' 'responses'; please forgive us.
        </p>
        <div class="more m1">
          <p>
            Thanx to <a href="http://docker.com" target="_blank">Docker</a>, everything is set for you:
          </p>
          <pre>
            <code>
> cd docker
> docker-compose up -d</code>
          </pre>
          </div>
          <h3>Tomcat</h3>
          <p>
            Don't forget the <a href="http://tomcat.apache.org/" target="_blank">Tomcat</a>! Download and unzip latest Tomcat bundle. You may delete the default web application. Register a new Tomcat installation in your IDE.
          </p>
          <p class="amore">
            <a href="#" onclick="return show(1);">View snippets &raquo;</a>
          </p>
        </div>
      </div>
    </div>


    <!-- BLOCK 2 ------------------------------------------------------------------------------------------------------------>


    <div id="block2" class="section">
      <a id="2"></a>
      <div id="scroller-anchor-2"></div>
      <a id="scroller-2" href="#2" class="scroller">
        <div class="circle">2</div>
      </a>
      <div class="vertical-line"></div>
      <div class="content">
        <div class="text">

          <h2>Build The Core</h2>

          <p>
            First thing's first. We need to build the simplest web app possible that works. Let's start!
          </p>

          <p>
            There are only 3 things we have to do for now:
          </p>

          <ul>
            <li>Add Gradle dependecies,</li>
            <li>Register the web application,</li>
            <li>Set the database connection properties.</li>
          </ul>

          <p class="info">
            Again, the source for this step awaits on <a href="https://github.com/oblac/tutorial/tree/master/step02">GitHub</a>!
          </p>


          <h3>Gradle dependencies</h3>

          <p>
            Obviously, we'll need to add some more dependencies: for the MySql driver and servlets jars.
          </p>

          <div class="more m2">
            <pre>
                <code>
dependencies {
    compile 'org.jodd:jodd-joy:4.1.1'
    runtime 'mysql:mysql-connector-java:5.1.45'

    providedRuntime 'javax.servlet:javax.servlet-api:4.1.0'
    providedRuntime 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.1'
}</code>
          </pre>
          </div>

          <h3>Web application</h3>

          <p>
            Though we can register the app in <code>web.xml</code>, it's easier to simply create a <code>WebListener</code> based on the <code>JoyContextListener</code> class. This is all we need for now: just an empty subclass annotated with
            <code>@WebListener</code> annotation.
          </p>

          <div class="more m2">
            <pre>
                <code>
@WebListener
  public class AppContextListener extends JoyContextListener {

  }</code>
          </pre>
          </div>

          <h3>Properties</h3>
          <p>
            By default, Jodd Joy properties are stored in the <code>joy.props</code> file, located in the classpath root. The props file is a powerful extension with Java properties. The initial properties just set the database connection and the connection pool.
          </p>

          <div class="more m2">
            <pre>
                <code>
# database
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jodd-tutorial?useSSL=false
jdbc.username=root
jdbc.password=root!

# db pool
dbpool.driver=${jdbc.driverClassName}
dbpool.url=${jdbc.url}
dbpool.user=${jdbc.username}
dbpool.password=${jdbc.password}
dbpool.maxConnections=50
dbpool.minConnections=5
dbpool.waitIfBusy=true</code>
      </pre>

            <p>
              Make sure that your IDE recognizes <code>*.props</code> files as resources.
            </p>

          </div>

          <h3>Run!</h3>
          <p>
            And that's all! These three simple steps are all you need to run the web application :)
          </p>

          <div class="more m2">
            <p>
              This is how the project looks like:
            </p>
            <p class="img">
              <img src="jodd-2-layout.png" alt="Layout">
            </p>

          </div>
          <p>
            Yes, you can start Tomcat now and check if everything works. Just watch Tomcat's log - the app should be up in a couple of seconds!
          </p>

          <p class="amore">
            <a href="#" onclick="return show(2);">View snippets &raquo;</a>
          </p>
        </div>
      </div>
    </div>


    <!-- BLOCK 3 ------------------------------------------------------------------------------------------------------------>


    <div id="block3" class="section">
      <a id="3"></a>
      <div id="scroller-anchor-3"></div>
      <a id="scroller-3" href="#3" class="scroller">
        <div class="circle">3</div>
      </a>
      <div class="vertical-line"></div>
      <div class="content">
        <div class="text">

          <h2>Show Me Some Messages</h2>

          <p>We can start coding our application! Let's display the last 10 messages on the index page.</p>

          <p class="info">
            This step requires some more coding.
            <a href="https://github.com/oblac/tutorial/tree/master/step03">Download it all</a> instead! Or go ahead and fire up that keyboard!
          </p>

          <h3>Model</h3>

          <p>
            We need two model classes: <code>Message</code> and <code>Response</code> (for comments). These will be mapped to the database tables. As they are simple POJOs, we just need to mark them with appropriate DbOom database mapping annotations.
          </p>

          <div class="more m3">
            <p>
              Message class:
            </p>

            <pre>
                <code>
@DbTable
public class Message {

    @DbId
    private long messageId;

    @DbColumn
    private String text;

    // ...getters and setters...
}</code>
      </pre>

            <p>
              ... and comments class:
            </p>

            <pre>
                <code>
@DbTable
public class Response {

    @DbId
    private long responseId;

    @DbColumn
    private String text;

    @DbColumn
    private long messageId;

    // ...getters and setters...
}</code>
      </pre>

            <p>Once again, simple POJOs with Jodd annotations.</p>
          </div>

          <p>
            Please note that we haven't said anything about the relationship between these two entities. We will discuss this in more detail later; for now, just keep in mind that Jodd is all about <i>mapping</i>, so relations are not defined up front. Instead, you'll define them with your queries <i>when needed</i>.
          </p>

          <h3>Database configuration</h3>

          <p>
            It's a good practice to use a prefix for the database tables that your application uses. We can specify the prefix in Jodd annotations, but it's better to specify a default prefix for all entity beans. You can do this in <code>joy.props</code>. While you're at it, we can also enable the debug mode for more verbose logs.
          </p>

          <div class="more m3">
            <pre>
                <code>
db.debug=true
db.dbOomConfig.tableNames.prefix=jd_
        </code>
      </pre>
          </div>

          <h3>Java Service</h3>

          <p>
            Finally, it's time to read the database and return the data! We are going to write a bean that contains the (business) logic. We will mark this bean as <code>@PetiteBean</code> to have it registered in the application's Petite container. No other registration is required!
          </p>

          <p>
            Since our method accesses the database, it has to run under a database transaction. To enable a database session for this method, we just need to mark it with a transactional annotation.
          </p>

          <p>
            Instead of SQL, we will write queries using T-SQL (Template SQL). It's an extension of the common SQL that provides special macros which may reference to our Java entities. This significantly simplifies writing native SQL queries!
          </p>

          <div class="more m3">
            <pre>
                <code>
@PetiteBean
public class AppService {

    @ReadOnlyTransaction
    public List&lt;Message&gt; findLastMessages(int count) {
        DbSqlBuilder dbsql =
            sql("select $C{m.*} from $T{Message m} " +
            "order by $m.messageId desc limit :count");
        DbOomQuery dbquery = query(dbsql);
        dbquery.setInteger("count", count);

        return dbquery.list(Message.class);
    }
}</code>
      </pre>

            <p>
              Our service is simple POJO class, annotated with <code>@PetiteBean</code> annotation. You need nothing else, no XML files, registration, etc. And you may use plain SQL queries instead if you wish so.
            </p>

            <p>
              Noticed the <code>@ReadOnlyTransaction</code> annotation? Yeah, that's all that's required to supply your database code with a transactional database session.
            </p>

          </div>

          <p>Awesome, right?!</p>

          <h3>View</h3>

          <p>
            For the web layer, we'll need a Madvoc action and JSP that renders the result. Madvoc action is a simple bean, annotated with <code>@MadvocAction</code>. Created on every request, Madvoc action recognizes the container's context and you can easily inject your services.
          </p>

          <div class="more m3">
            <pre>
                <code>
@MadvocAction
public class IndexAction {

    @PetiteInject
    AppService appService;

    @Out
    List&lt;Message&gt; messages;

    @Action
    public void view() {
        messages = appService.findLastMessages(10);
    }
}</code>
      </pre>

            <p>
              Madvoc actions are automatically registered by default. You can use manual registration instead!
            </p>
          </div>

          <p>
            Madvoc action uses simple conventions and smart annotation to define input and outputs and target JSP. Our example has only one output – a list of messages.
          </p>

          <div class="more m3">
            <pre>
                <code>
&lt;%@ taglib prefix=&quot;j&quot; uri=&quot;/jodd&quot; %&gt;
&lt;html&gt;
&lt;body&gt;
&lt;h1&gt;Messages&lt;/h1&gt;

&lt;ul&gt;
&lt;j:iter items=&quot;${messages}&quot; var=&quot;msg&quot;&gt;
    &lt;li&gt;${msg.messageId} ${msg.text}
&lt;/j:iter&gt;
&lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;</code>
      </pre>

            <p>
              Another gem for you: there is an entire powerful tag library you can use in your JSPs!
            </p>
          </div>

          <h3>Run!</h3>

          <p>
            Start Tomcat and go to <code>http://localhost:8080/index.html</code>. You will see the last 10 messages!
          </p>

          <p class="amore">
            <a href="#" onclick="return show(3);">View snippets &raquo;</a>
          </p>
        </div>
      </div>
    </div>

    <!-- BLOCK 4 ------------------------------------------------------------------------------------------------------------>

    <div id="block4" class="section">
      <a id="4"></a>
      <div id="scroller-anchor-4"></div>
      <a id="scroller-4" href="#4" class="scroller">
        <div class="circle">4</div>
      </a>
      <div class="vertical-line"></div>
      <div class="content">
        <div class="text">

          <h2>Messages and Comments</h2>

          <p>
            It's time to display messages-related comments.
          </p>

          <p class="info">
            Only few changes ahead! Still, you may
            <a href="https://github.com/oblac/tutorial/tree/master/step04">checkout the updates</a>.
          </p>

          <h3>Model</h3>

          <p>
            Add a list of <code>Response</code> objects to the <code>Message</code> class as a simple property. It will hold comments, but only when we want so. It's important to remember this: related comments will not be automatically pre- or lazy-fetched. Instead, we just map them and use them when we want to. Alternatively, you can use different beans, depending on the relationship you need.
          </p>

          <div class="more m4">
            <pre>
                <code>
@DbTable
public class Message {

    ...

    private List&lt;Response&gt; responses;

    public List&lt;Response&gt; getResponses() {
        return responses;
    }

}</code>
      </pre>

            <p>
              Note that <code>responses</code> is a read-only property. There is no special rule about this, it's just how we want to have it in this tutorial.
            </p>

          </div>

          <h3>Service</h3>

          <p>
            To fetch all messages and their (optional) comments, we need a left join between these two tables. If we simply change the query and add additional mapping, then each row of the result set will be mapped to <code>Object[2]</code> – it will hold the message and its single comment. We don't want that! Instead, we want to have a single message filled up with all its comments (stored in the new property). Here's an easy way to do it.
          </p>

          <p>
            First, we inject comments into messages. Using DbOom <i>hints</i> lets us specify T-SQL so that one result object is injected or added into the property of another resulting object. In our case, we can define that <code>Response</code> object is added into the new list property of <code>Message</code> class.
          </p>

          <p>
            Secondly, we prevent the repetition of messages with the same id. When a message has more than one comment, the same message data will be repeated in the joined results for each comment. This would give us many <code>Message</code> instances of the same entity (i.e. with the same ID). To fix this, we just need to enable <i>entityAware</i> mode that caches entities during the lifetime of a query.
          </p>

          <div class="more m4">
            <pre>
                <code>
@Transaction
public List&lt;Message&gt; findLastMessagesWithResponses(int count) {
    DbSqlBuilder dbsql = sql(
            "select $C{m.*}, $C{m.responses:r.*} " +
            "from $T{Message m} " +
            "left join $T{Response r} using ($.messageId) " +
            "order by $m.messageId desc limit :count");

    DbOomQuery dbquery = query(dbsql);
    dbquery.entityAwareMode(true);
    dbquery.setInteger("count", count);

    return dbquery.list(Message.class, Response.class);
}</code>
      </pre>

            <p>
              When <i>entityAware</i> mode is enabled, two things will happen. First, all entities during the lifetime of a query will be cached, so there will be no two instances of the same entity.Second, the result set rows will be compacted if needed. For example, if one message has two comments, that would give two rows in the result set. Compaction gives us one message with two comments in the list.
            </p>

          </div>

          <h3>View</h3>

          <p>
            The change in the web layer is trivial. Our action has to call a new method and JSP has to display the message comments.
          </p>

          <div class="more m4">
            <pre>
                <code>
&lt;ul&gt;
&lt;j:iter items=&quot;${messages}&quot; var=&quot;msg&quot;&gt;
    &lt;li&gt;${msg.messageId} ${msg.text}
        &lt;ul&gt;
            &lt;j:iter items=&quot;${msg.responses}&quot; var=&quot;resp&quot;&gt;
                &lt;li&gt;${resp.responseId} ${resp.text}&lt;/li&gt;
            &lt;/j:iter&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
&lt;/j:iter&gt;
&lt;/ul&gt;</code>
      </pre>

            <p>
              If everything goes well, the output should look like this:
            </p>
            <p class="img">
              <img src="jodd-4-page.png" alt="output">
            </p>
          </div>


          <p class="amore">
            <a href="#" onclick="return show(4);">View snippets &raquo;</a>
          </p>
        </div>
      </div>
    </div>

    <!-- BLOCK 5 ------------------------------------------------------------------------------------------------------------>


    <div id="block5" class="section">
      <a id="5"></a>
      <div id="scroller-anchor-5"></div>
      <a id="scroller-5" href="#5" class="scroller">
        <div class="circle">5</div>
      </a>
      <div class="vertical-line"></div>
      <div class="content">
        <div class="text">

          <h2>Add A New Message</h2>

          <p>
            So far, we've just been reading from the database. Let's see now how to add some new messages.
          </p>

          <p class="info">
            Congratulations, we are almost done!
            <a href="https://github.com/oblac/tutorial/tree/master/step05">Keep track</a> with code changes or just type them along with us!
          </p>

          <h3>Service</h3>

          <p>
            Jodd provides shortcuts for common database operation. You don't have to write queries for storing entities, searching for them by ID or property value, updating, deleting, etc. With the help of <code>DbEntitySql</code> you can write simple one-liner calls in Java to get the same result.
          </p>

          <div class="more m5">
            <pre>
                <code>
@ReadWriteTransaction
public void addMessage(Message message) {
    DbEntitySql
            .insert(message)
            .query()
            .autoClose()        // not mandatory, but nice
            .executeUpdate();
}</code>
      </pre>
          </div>

          <p>
            This time, however, we need to mark the service method with a different Jodd's transaction annotation, which signals that the transaction is not read-only.
          </p>

          <h3>View</h3>

    <p>
        Obviously, there will be more changes to the web layer. We need two more actions: one to show a page with a form, and the other to handle form submissions. We can define both actions in the same class, which is convenient. The form handler won't have any extension and will handle only <code>POST</code> requests.
    </p>

    <div class="more m5">
        <pre>
          <code>
@MadvocAction
public class MessageAction {

    @PetiteInject
    AppService appService;

    @Action
    public void view() {
    }

    @In
    Message message;

    @POST @Action
    public String add() {
        appService.addMessage(message);
        return "redirect:/&lt;index&gt;";
    }
}</code>
      </pre>

        <p>
            This action defines two mappings: <code>/message.html</code> mapped to the <code>#view()</code>
            method and <code>/message.add</code> mapped to the <code>#add()</code> method. The first action handler
            just renders the form with the <code>message.jsp</code> page. The second action handler stores submitted message.
        </p>

        <pre>
          <code>
&lt;html&gt;
&lt;body&gt;
&lt;h1&gt;Add Message&lt;/h1&gt;

&lt;form action=&quot;/message.add&quot; method=&quot;POST&quot;&gt;
    &lt;textarea name=&quot;message.text&quot; rows=&quot;5&quot; cols=&quot;50&quot;&gt;
    &lt;/textarea&gt;
    &lt;button type=&quot;submit&quot;&gt;Submit&lt;/button&gt;
&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;</code>
      </pre>

        <p>
            There is one thing to notice here - the name of the parameter: "<code>message.text</code>".
            It specifies where the submitted value will be injected into. Since the <code>message</code>
            property of the action is marked with <code>@In</code>, text value will be inserted into
            message property <code>text</code>, after a new instance of <code>Message</code> is created.
        </p>
    </div>

    <p>
        After the new message is submitted and stored in the database, we'll want to redirect to the index page. While we can just hardcode the page path, there are better ways to go about it. One way is to use <i>aliases</i>. Each action method has its alias name and that alias handle represents an action path. So even if you change your code and rename the handler method, Jodd will find the aliased target path.
    </p>

    <h3>Alternatives</h3>

          <p>
            There is even a shorter alternative for basic manipulation of an entity. By using <code>GenericDao</code> (or somewhat enhanced <code>AppDao</code>) you can perform basic database operation using just a single method call.
          </p>

          <div class="more m5">
            <pre>
                <code>
@PetiteInject
AppDao appDao;

@ReadWriteTransaction
public void addMessageAlt(Message message) {
    appDao.store(message);
}</code>
      </pre>
          </div>

          <p>
            There is another option: use <code>Result</code> to specify the redirection in the web action. With this helper class you can define a handle for any action method by calling it! Then you don't need to define any custom aliases for actions.
          </p>


          <div class="more m5">
            <pre>
                <code>
@MadvocAction
public class MessageAction {

    final Result result = new Result();

    @POST @Action
    public void add() {
        appService.addMessageAlt(message);
        result.redirectTo(IndexAction.class).view();
    }

}</code>
      </pre>

            <p>
              <code>Result</code> instances don't have to be explicitly instantiated as shown above. You can use any <code>Result</code> <i>subclasses</i> with your additional helper methods.
            </p>
          </div>

          <p>
            The alternative code works the same. It's up to you to decide what to use :) That's what makes Jodd beautiful :)
          </p>

          <h3>Run</h3>

          <p>
            Run your web application again. Go to the <a href="http://localhost:8080/message.html">message page</a> and add new messages. It's fun! :)
          </p>

          <p class="amore">
            <a href="#" onclick="return show(5);">View snippets &raquo;</a>
          </p>
        </div>
      </div>
    </div>

    <!-- BLOCK 6 ------------------------------------------------------------------------------------------------------------>

    <div id="block6" class="section">
      <a name="6"></a>
      <div id="scroller-anchor-6"></div>
      <a id="scroller-6" href="#6" class="scroller">
        <div class="circle">6</div>
      </a>
      <div class="vertical-line"></div>
      <div class="content">
        <div class="text">

          <h2>Give Me Some REST!</h2>

          <p>
            Jodd is quite flexible: there are always several different ways to get to the same result. Adding a REST api is easy: instead of using <code>@Action</code>, we can use <code>@RestAction</code>! However, each annotation comes with a different configuration. The <code>@RestAction</code> uses a different mapping convention: action method names should now start with HTTP method names.
          </p>

          <p>
            Let's add a new action class: <code>MessageAction</code> and action method <code>get()</code>. There is also a nice way to specify path patterns that will be matched and populated into the <code>@In</code> parameters. Just use string template and <code>{}</code> macros.
          </p>


          <div class="more m6">
            <pre>
                <code>
@MadvocAction
public class MessageAction {

    @PetiteInject
    AppService appService;

    @RestAction("{messageId}")
    public Message get(@In long messageId) {
        return appService.findMessageById(messageId);
    }</code>
          </pre>
          </div>

          <p class="info">
            See the <a href="https://github.com/oblac/tutorial/tree/master/step06">REST code changes</a> - there are more tricks inside!
          </p>

          <p>
            And that's it! Return a message object and it will be serialized to JSON.
          </p>

        </div>
      </div>
    </div>

    <!-- BLOCK 7 ------------------------------------------------------------------------------------------------------------>

    <div id="block7" class="section last">
      <!-- <div id="scroller-anchor-7"></div>
      <div id="scroller-7" class="circle theme-lightgray">7</div> -->
      <div class="content">
        <div class="text">

          <h2>What We Have Learned?</h2>

          <p>
            We hope this tutorial has got you interested in Jodd. You have learned the essentials of core Jodd micro-frameworks. There is a <i>Petite</i> dependency-injection container to glue the components together. We use <i>Madvoc</i> for the web layer. We communicated with the database using the <i>DbOom</i> mapper, enabling the JTX transaction using the <i>Proxetta</i> proxies. And all the application components were simple beans, marked just with annotations.
          </p>

          <p>
            In our tutorial, we use Jodd <i>Joy</i> - an application template for faster web application development. It is quite configurable and combines the best Jodd practices with a pragmatic approach.
          </p>

          <p>
            Possibly the single most important thing to learn here is that Jodd doesn't offer a single out-of-the-box solution that claims to magically solve all the problems. Instead, Jodd provides solid, but lightweight frameworks; it gives you the freedom to code your solutions the way you want.
          </p>


          <h2>And Beyond!</h2>

          <p>
            There are many other Jodd features not that we haven't covered in this tutorial, such as various micro-frameworks you might like to use in your application... You may continue by adding <i>Decora</i> page templates for the entire site. Then you can optimize resources using <i>HtmlStapler</i>. Why not add authentication and authorization interceptors? Forms may be validated using <i>VTor</i>. Or, you can add more proxies using <i>Proxetta</i>. If you need to send some emails, fire a few HTTP requests, parse some HTML as if using jQuery; or just need simple utility methods... Jodd has it all.
          </p>

          <h2><a href="http://jodd.org">http://jodd.org</a></h2>

          <p class="gap" style="margin-top:120px; font-size: 14px;">
            Built by Igor &amp; friends with <span style="font-size:1.4em;">❤</span>.
          </p>

        </div>
      </div>
    </div>

    <div class="scroll-up">
      <a href="">
        <em>visit</em> <br>
        jodd.org
      </a>
      <span>
        <img src="up-icon.svg" alt="up">
      </span>
    </div>

    <div class="loop-logo">
      <img src="jodd-logo.svg" alt="logo">
    </div>

    <div class="loop-logo inverted">
      <img src="jodd-logo.svg" alt="logo inverted">
    </div>

  </body>
  <script type="text/javascript" src="js/jquery-min.js"></script>
  <script type="text/javascript" src="js/main.js"></script>

</html>
